package com.zky.gulimall.product;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description TODO
 * @Author 张开源
 * @Date 2023/2/22 18:33
 * @Version 1.0
 **/
@SpringBootTest
@Slf4j
@RunWith(SpringRunner.class)
public class interview {
    public static Map<String, String> map = new HashMap<>();

    static {
        map.put("1", "aa");
        map.put("2", "bb");
        map.put("3", "cc");
        map.put("4", "dd");
    }

    //遍历map的key和value,方式一
    @Test
    public void test1() {
        for (String s : map.keySet()) {
            System.out.println("key=" + s + "|value=" + map.get(s));
        }
    }


    //遍历map的key和value,方式二
    @Test
    public void test2() {
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("key=" + entry.getKey() + "|value=" + entry.getValue());
        }
    }

    //遍历map的key和value,方式三，迭代器
    @Test
    public void test3() {
        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> next = iterator.next();
            System.out.println("key=" + next.getKey() + "value=" + next.getValue());
        }
    }

    //遍历map的value,方式四,只能遍历value
    @Test
    public void test4() {
        for (String value : map.values()) {
            System.out.println("value=" + value);
        }
    }

    //获取年月日时分秒
    @Test
    public void test5() {
        Date t = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(df.format(t));
    }

    //获取年月日时分秒
    @Test
    public void test6() {
        LocalDateTime localDateTime = LocalDateTime.now();
        String format = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println(format);
    }


    //打印*倒立三角
    @Test
    public void test7() {
        print(10);
    }

    private void print(int n) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                System.out.print(" ");
            }
            for (int j = 0; j < n - i; j++) {
                System.out.print("* ");
            }
            System.out.println();
        }
    }


    private final static int THREAD_COUNT = 3;
    static int result = 0;
    static int maxNum = 20;

    //交替打印
    @Test
    public void test8() {
        final Semaphore[] semaphores = new Semaphore[THREAD_COUNT];
        for (int i = 0; i < THREAD_COUNT; i++) {
            //非公平信号量，每个信号量初始计数都为1
            semaphores[i] = new Semaphore(1);
            if (i != THREAD_COUNT - 1) {
                System.out.println(i + "===" + semaphores[i].getQueueLength());
                //获取一个许可前线程将一直阻塞, for 循环之后只有 syncObjects[2] 没有被阻塞
                try {
                    semaphores[i].acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        for (int i = 0; i < THREAD_COUNT; i++) {
            // 初次执行，上一个信号量是 syncObjects[2]
            final Semaphore lastSemphore = i == 0 ? semaphores[THREAD_COUNT - 1] : semaphores[i - 1];
            final Semaphore currentSemphore = semaphores[i];
            final int index = i;
            new Thread(() -> {
                try {
                    while (true) {
                        // 初次执行，让第一个 for 循环没有阻塞的 syncObjects[2] 先获得令牌阻塞了
                        lastSemphore.acquire();
                        System.out.println("thread" + index + ": " + result++);
                        if (result > maxNum) {
                            System.exit(0);
                        }
                        // 释放当前的信号量，syncObjects[0] 信号量此时为 1，下次 for 循环中上一个信号量即为syncObjects[0]
                        currentSemphore.release();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }


    @Test
    public void test9() {
        Thread t1 = new Thread(new MyThread2(0));
        Thread t2 = new Thread(new MyThread2(1));
        Thread t3 = new Thread(new MyThread2(2));
        t1.start();
        t2.start();
        t3.start();
    }

    static class MyThread2 implements Runnable {

        private int no;

        private static ReentrantLock lock = new ReentrantLock();

        private static Condition condition = lock.newCondition();

        private static int count;

        public MyThread2(int no) {
            this.no = no;
        }

        @Override
        public void run() {
            lock.lock();

            try {
                while (true) {
                    if (count >= 100) {
                        break;
                    } else {
                        if (count % 3 == this.no) {
                            count++;
                            System.out.println(this.no + "-->" + count);
                        } else {
                            try {
                                condition.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    condition.signalAll();
                }
            } finally {
                //最后要释放锁，不然会导致死锁
                lock.unlock();
            }
        }
    }

    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private Condition condition4 = lock.newCondition();
    private Condition condition5 = lock.newCondition();
    private Condition condition6 = lock.newCondition();
    private Condition condition7 = lock.newCondition();
    private Condition condition8 = lock.newCondition();

    static int count;

    @Test
    public void test10() {
        new Thread(() -> {
            try {
                lock.lock();
                count++;
                System.out.println("ThreadName:" + Thread.currentThread().getName() + "| count=" + count);
                condition1.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "线程1").start();

        new Thread(() -> {
            try {
                lock.lock();
                count++;
                System.out.println("ThreadName:" + Thread.currentThread().getName() + "| count=" + count);
                condition1.signal();
                condition2.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "线程2").start();

        new Thread(() -> {
            try {
                lock.lock();
                count++;
                System.out.println("ThreadName:" + Thread.currentThread().getName() + "| count=" + count);
                condition2.signal();
                condition3.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "线程3").start();

        new Thread(() -> {
            try {
                lock.lock();
                count++;
                System.out.println("ThreadName:" + Thread.currentThread().getName() + "| count=" + count);
                condition3.signal();
                condition4.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "线程4").start();

        new Thread(() -> {
            try {
                lock.lock();
                count--;
                System.out.println("ThreadName:" + Thread.currentThread().getName() + "| count=" + count);
                condition4.signal();
                condition5.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "线程5").start();

        new Thread(() -> {
            try {
                lock.lock();
                count--;
                System.out.println("ThreadName:" + Thread.currentThread().getName() + "| count=" + count);
                condition5.signal();
                condition6.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "线程6").start();

        new Thread(() -> {
            try {
                lock.lock();
                count--;
                System.out.println("ThreadName:" + Thread.currentThread().getName() + "| count=" + count);
                condition6.signal();
                condition7.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "线程7").start();

        new Thread(() -> {
            try {
                lock.lock();
                count--;
                System.out.println("ThreadName:" + Thread.currentThread().getName() + "| count=" + count);
                condition7.signal();
                condition8.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "线程8").start();
    }


    @Test
    public void test12(){
        int[] arr={0,1};
        boolean b = canPlaceFlowers(arr, 2);
        System.out.println(b);

        boolean b1 = canPlaceFlowers1(arr, 3);
        System.out.println(b1);
    }

    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        //长度为1并且只种一棵树并且正好有一个空位， Okay！
        if (flowerbed.length == 1 && n == 1 && flowerbed[0] == 0) {
            return true;
        }
        int length = flowerbed.length;
        int count = 0;
        //判断是否能种植， 需要判断前一个位置是否为0
        //以及后一个位置是否为0
        //特殊情况是i为0 ， 以及i为length - 1
        //就是第一个和最后一个啦
        for (int i = 0; i < length; i++) {
            if (flowerbed[i] == 0) {
                if ((i - 1 >= 0 && flowerbed[i - 1] == 0) || (i == 0 && i + 1 < length && flowerbed[i + 1] == 0)) {
                    if ((i + 1 < length && flowerbed[i + 1] == 0) || (i == length - 1 && i - 1 >= 0 && flowerbed[i - 1] == 0)) {
                        count++;
                        flowerbed[i] = 1;
                    }
                }
            }
        }

        if (n <= count) {
            return true;
        } else {
            return false;
        }
    }


    public boolean canPlaceFlowers1(int[] flowerbed, int n) {
        // 对flowerbed进行遍历
        for(int i = 0; i < flowerbed.length; ++i) {
            if(n == 0) {	// n等于0的时候便可提前终止循环
                break;
            }
            if(flowerbed[i] == 0) {	// 当此处未种花时
                // 判断倒底能否种花
                // 中间的地方就是左右都是0便可以种
                // 最左边是只要其右边是0就可以种，最右边反之
                if((i - 1 == -1 || flowerbed[i-1] == 0) && (i + 1 == flowerbed.length || flowerbed[i+1] == 0)) {
                    flowerbed[i] = 1;	// 赋值1代表种花
                    --n;	// 花的总数-1，直到减到0
                }
            }
        }
        return n == 0;
    }


}
